package com.wiz.web.manager;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.ConnectionPoolTimeoutException;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import com.wiz.common.Constant;
import com.wiz.vo.to.lamicpay.LamicReqData;
import com.wiz.vo.to.wjika.WjPayReqData;

/**
 * 协议管理器
 * @author Hakeny
 */
@Service("httpManager")
public class HttpManager implements Constant{
	private transient final Logger log = LoggerFactory.getLogger(getClass());
	
	private final int poolThreads = 200;
	private PoolingHttpClientConnectionManager cm;
	private CloseableHttpClient cc;
	private RequestConfig requestConfig = RequestConfig.custom()
			.setSocketTimeout(30000).setConnectTimeout(30000).build();

	/**
	 * 获得工厂管理器，以此配置形式新建工厂
	 * @return
	 */
	private synchronized PoolingHttpClientConnectionManager getPHCManagerInstance() {
		if (cm == null) {
			cm = new PoolingHttpClientConnectionManager();
			// 连接池最大生成连接数200
			cm.setMaxTotal(poolThreads);
			// 设置默认(连接url)route最大连接数为200，即并发线程数,目前只直连了评论系统，故最大连接数与此值相同
			cm.setDefaultMaxPerRoute(poolThreads);
			// 实例：指定专门的route，设置最大连接数为50，可设置多个，但总数不可超过MaxTotal
			// HttpHost localhost=new HttpHost("192.168.0.198", 7041);
			// cm.setMaxPerRoute(new HttpRoute(localhost), 500);
		}
		return cm;
	}

	/**
	 * 获得http链接工厂
	 * @return
	 */
	private synchronized CloseableHttpClient getCloseableHttpClient() {
		if (cc == null) {
			cc = HttpClients.custom().setConnectionManager(getPHCManagerInstance()).build();
		}
		return cc;
	}
	
	/*<xml><return_code><![CDATA[SUCCESS]]></return_code>
	<return_msg><![CDATA[OK]]></return_msg>
	<appid><![CDATA[wx5d7213f7ae8e6fdf]]></appid>
	<mch_id><![CDATA[1295677401]]></mch_id>
	<nonce_str><![CDATA[OrRq6rjJTL1GhGqs]]></nonce_str>
	<sign><![CDATA[1F59257EA22EF76F6C750992275792FF]]></sign>
	<result_code><![CDATA[FAIL]]></result_code>
	<err_code><![CDATA[ORDERPAID]]></err_code>
	<err_code_des><![CDATA[该订单已支付]]></err_code_des>
	</xml>*/

	/**
	 * 微信要求格式请求
	 * @param url
	 * @param xmlObj
	 * @return
	 */
	public String sendWxPost(String url, Object xmlObj) {
		String result = "fail";
		HttpPost httpPost = new HttpPost(url);
		// 解决XStream对出现双下划线的bug
		XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8",
				new XmlFriendlyNameCoder("-_", "_")));
		// 将要提交给API的数据对象转换成XML格式数据Post给API
		String postDataXML = xStreamForRequestPostData.toXML(xmlObj);
//		System.out.println(postDataXML);
		// 得指明使用UTF-8编码，否则到API服务器XML的中文不能被成功识别
		StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
		httpPost.addHeader("Content-Type", "text/xml");
		httpPost.setEntity(postEntity);
		httpPost.setConfig(requestConfig);
		try {
//			CloseableHttpClient httpClient = HttpClients.createDefault();
			CloseableHttpClient httpClient = getCloseableHttpClient();
			HttpResponse response = httpClient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			result = EntityUtils.toString(entity, "UTF-8");
		} catch (ConnectionPoolTimeoutException e) {

		} catch (ConnectTimeoutException e) {

		} catch (SocketTimeoutException e) {

		} catch (Exception e) {

		} finally {
			httpPost.abort();
		}
		return result;
	}
	
	/**
	 * 讯联要求格式请求
	 * @param url
	 * @param xmlObj
	 * @return
	 */
	public String sendXlPost(String url, String params) {
		String result = "fail";
		HttpPost httpPost = new HttpPost(url);
//		System.out.println(postDataXML);
		// 得指明使用UTF-8编码，否则到API服务器XML的中文不能被成功识别
		StringEntity postEntity = new StringEntity(params, "UTF-8");
		httpPost.addHeader("Content-Type", "text/xml");
		httpPost.setEntity(postEntity);
		httpPost.setConfig(requestConfig);
		try {
			CloseableHttpClient httpClient = getCloseableHttpClient();
			HttpResponse response = httpClient.execute(httpPost);
			HttpEntity entity = response.getEntity();
			result = EntityUtils.toString(entity, "UTF-8");
			log.info("response================="+result);
		} catch (ConnectionPoolTimeoutException e) {

		} catch (ConnectTimeoutException e) {

		} catch (SocketTimeoutException e) {

		} catch (Exception e) {

		} finally {
			httpPost.abort();
		}
		return result;
	}
	
	/**
	 * 万集post请求
	 * @return
	 */
	public String sendWjPost(String host,String uri,WjPayReqData reqData){
		List<NameValuePair> formparams = reqData.toFormParamsList();
		try {
			return getHttpResponseByPost(host, uri, formparams);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 莱米post请求
	 * @return
	 */
	public String sendLamicPost(String host,String uri,LamicReqData reqData){
		List<NameValuePair> formparams = reqData.toFormParamsList();
		try {
			return getHttpResponseByPost(host, uri, formparams);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public String getLamicEncryptResult(String str){
		List<NameValuePair> formparams=new ArrayList<NameValuePair>();
		formparams.add(new BasicNameValuePair("str", str));
		try {
			return getHttpResponseByPost(LAMIC_IP, LAMIC_ENCRYPT, formparams);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public String getLamicEncryptResults(String str){
		List<NameValuePair> formparams=new ArrayList<NameValuePair>();
		formparams.add(new BasicNameValuePair("strs", str));
		try {
			return getHttpResponseByPost(LAMIC_IP, LAMIC_ENCRYPT_PARAMS, formparams);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public String memberCharge(String hqId,String openId,Integer chargeAmount,String refId){
		List<NameValuePair> formparams=new ArrayList<NameValuePair>();
		formparams.add(new BasicNameValuePair("openId", openId));
		formparams.add(new BasicNameValuePair("hqId", hqId));
		formparams.add(new BasicNameValuePair("refId", refId));
		formparams.add(new BasicNameValuePair("chargeAmount", String.valueOf(chargeAmount)));
		formparams.add(new BasicNameValuePair("channel", String.valueOf(4)));
		try {
			return getHttpResponseByPost(CENTER_URL, CENTER_CHARGE_URI, formparams);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (URISyntaxException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	private String getHttpResponseByGet(String url) 
			throws ClientProtocolException, IOException, URISyntaxException {
		URI uri= new URIBuilder(url).build();
		CloseableHttpClient httpClient = getCloseableHttpClient();
		HttpGet httpget = new HttpGet(uri);
		httpget.setConfig(requestConfig);
		CloseableHttpResponse response = null;
		response = httpClient.execute(httpget, HttpClientContext.create());
		return getResponseContent(response);
	}
	
	private String getHttpResponseByPost(String host, String path,
			List<NameValuePair> formparams) throws URISyntaxException,ClientProtocolException,IOException {
		CloseableHttpClient httpClient = getCloseableHttpClient();
		UrlEncodedFormEntity entity = new UrlEncodedFormEntity(formparams,Consts.UTF_8);
		URI uri = new URIBuilder().setScheme("http").setHost(host).setPath(path).build();
		HttpPost httppost = new HttpPost(uri);
		httppost.setEntity(entity);
		httppost.setConfig(requestConfig);
		CloseableHttpResponse response = httpClient.execute(httppost,HttpClientContext.create());
		return getResponseContent(response);
	}
	
	/**
	 * 获取response中的内容
	 * @param response
	 * @return
	 */
	private String getResponseContent(CloseableHttpResponse response) {
		String content = "";
		if (response != null) {
			HttpEntity httpEntity = response.getEntity();
			try {
				if (response.getStatusLine().getStatusCode() == 200) {
					if (httpEntity != null) {
						content = EntityUtils.toString(httpEntity);
					}
				} 
				//处理http返回码302的情况  
				else if (response.getStatusLine().getStatusCode() == 302) {
				    String locationUrl = response.getLastHeader("Location").getValue();
				    return getHttpResponseByGet(locationUrl);//跳转到重定向的url  
			    } 
				else{
					return content;
				}
			} catch (Exception e) {
				return content;
			} finally {
				try {
					if (httpEntity != null) {
						httpEntity.getContent().close();
					}
					response.close();
				} catch (IOException e) {
				}
			}
		}
		return content;
	}
}
